﻿using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using UtilZ.Dotnet.Ex.DataStruct;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.Ex.Model;

namespace WpfApp
{
    /// <summary>
    /// TestDataMerger.xaml 的交互逻辑
    /// </summary>
    unsafe public partial class TestDataMerger : Window
    {
        public TestDataMerger()
        {
            InitializeComponent();
        }


        private ValueTypeDataMerger<int> _dataMerger = null;
        private AutoResetEvent _waitHandler = null;
        private readonly object _lock = new object();
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var redirectAppenderToUI = (RedirectAppender)Loger.GetAppenderByName(null, "RedirectToUI");
            if (redirectAppenderToUI != null)
            {
                redirectAppenderToUI.RedirectOuput += RedirectLogOutput;
            }

            var options = new ValueTypeDataMergerOptions()
            {
                InitCapcity = 4,
                LimitCapcity = 8,
                Limit = 8,
                TimeoutTrue = true,
                FullMode = ContainerFullMode.DropOld
            };
            this._dataMerger = new ValueTypeDataMerger<int>(options);
            this._waitHandler = new AutoResetEvent(false);
        }

        private void RedirectLogOutput(object sender, RedirectOuputArgs e)
        {
            string str;
            try
            {
                str = string.Format("{0} {1}", DateTime.Now, e.Item.Content);
            }
            catch (Exception ex)
            {
                str = ex.Message;
            }

            logControl.AddLog(str, e.Item.Level);
        }



        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (this._waitHandler != null)
            {
                this._waitHandler.Dispose();
                this._waitHandler = null;
            }

            var cts = _cts;
            if (cts != null)
            {
                cts.Cancel();
                cts.Dispose();
            }
        }



        private void btnProduce_Click(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(TestSC);
        }


        private void TestSC()
        {
            try
            {
                //this.Append(7);
                ////var data1 = this._dataMerger.Take(7);
                //this.Append(5);
                this.Append(10);

                //this.Append(1);
                this.Append(2);
                this.Append(4);
                this.Append(10);

                //var data1 = this._dataMerger.Take(17);
                this.Append(5);
                this.Append(5);

                //var data2 = this._dataMerger.Take(this._dataMerger.Length);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private int[] _buffer = new int[20];
        private int _value = 1;
        private void Append(int count)
        {
            for (int i = 0; i < count; i++)
            {
                this._buffer[i] = this._value++;
            }

            lock (this._lock)
            {
                this._dataMerger.Append(this._buffer, 0, count);
            }
            Loger.Debug($"Append:Count{count} ({string.Join('-', this._buffer.Take(count))})");
            this._waitHandler.Set();
            Thread.Sleep(1000);
        }

        private CancellationTokenSource _cts = null;
        private void btnConsume_Click(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(TestXF);
        }
        private void TestXF()
        {
            try
            {
                _cts = new CancellationTokenSource();
                int count = 4;
                // DataSpan<int> data;
                //int[] data;
                //Span<int> data;
                int[] data = new int[count + 1];

                while (!_cts.Token.IsCancellationRequested)
                {
                    if (this._dataMerger.Length < count)
                    {
                        this._waitHandler.WaitOne(100);
                        if (_cts.Token.IsCancellationRequested)
                        {
                            Loger.Info("IsCancellationRequested");
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }

                    lock (this._lock)
                    {
                        //data = this._dataMerger.TakeBufferData(count);
                        //Loger.Info($"TestXF.TakeBufferData-ok:{string.Join(",", data.Buffer.Skip(data.Offset).Take(data.Length))}");

                        //data = this._dataMerger.Take(count);
                        //Loger.Info($"TestXF.Take-ok:{string.Join(",", data)}");

                        //data = this._dataMerger.TakeSpan(count);
                        //Loger.Info($"TestXF.TakeSpan-ok:{string.Join(",", data.ToArray())}");

                        this._dataMerger.Take(data, 0, count);
                        Loger.Info($"TestXF.Take_buffer-ok:{string.Join(",", data.Take(count))}");
                    }
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }



        private void btnTailConsume_Click(object sender, RoutedEventArgs e)
        {
            Task.Factory.StartNew(TestTailXF);
        }
        private void TestTailXF()
        {
            try
            {
                _cts = new CancellationTokenSource();
                int count = 20;
                //DataSpan<int> data;
                //int[] data;
                //Span<int> data;
                int[] data = new int[count + 1];

                while (!_cts.Token.IsCancellationRequested)
                {
                    if (this._dataMerger.Length < count)
                    {
                        this._waitHandler.WaitOne(100);
                        if (_cts.Token.IsCancellationRequested)
                        {
                            Loger.Info("IsCancellationRequested");
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }

                    lock (this._lock)
                    {
                        //data = this._dataMerger.TakeTailBufferData(count);
                        //Loger.Info($"TestXF.TakeTailBufferData-ok:{string.Join(",", data.Buffer.Skip(data.Offset).Take(data.Length))}");

                        //data = this._dataMerger.TakeTail(count);
                        //Loger.Info($"TestXF.TakeTail-ok:{string.Join(",", data)}");

                        //data = this._dataMerger.TakeTailSpan(count);
                        //Loger.Info($"TestXF.TakeTailSpan-ok:{string.Join(",", data.ToArray())}");

                        this._dataMerger.TakeTail(data, 0, count);
                        Loger.Info($"TestXF.TakeTail_buffer-ok:{string.Join(",", data.Take(count))}");
                    }
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }



        private void btnCancell_Click(object sender, RoutedEventArgs e)
        {
            var cts = _cts;
            if (cts != null)
            {
                cts.Cancel();
            }
        }

        private void btnClearLog_Click(object sender, RoutedEventArgs e)
        {
            logControl.Clear();
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            _value = 1;
            this._dataMerger.Clear();
        }

        private void btnTakeBufferData_Click(object sender, RoutedEventArgs e)
        {
            var options = new ValueTypeDataMergerOptions() { InitCapcity = 7, LimitCapcity = 7 };
            var dataMerger = new ValueTypeDataMerger<int>(options);

            dataMerger.Append(new int[] { 1, 2, 3 });
            SpanZ<int> dataSpan = dataMerger.TakeSpanZ(2);
            string str1 = dataSpan.ToString(',');

            dataMerger.Append(new int[] { 4, 5, 6 });
            SpanZ<int> dataSpan2 = dataMerger.TakeSpanZ(2);
            string str2 = dataSpan2.ToString(',');

            SpanZ<int> dataSpan3 = dataMerger.TakeSpanZ(dataMerger.Length);
            string str3 = dataSpan3.ToString(',');

            dataMerger.Append(new int[] { 7, 8, 9 });
            SpanZ<int> dataSpan4 = dataMerger.TakeSpanZ(2);
            string str4 = dataSpan4.ToString(',');

        }

        private void btnTake2_Click(object sender, RoutedEventArgs e)
        {
            var options = new ValueTypeDataMergerOptions() { InitCapcity = 5, LimitCapcity = 5 };
            using var dataMerger = new ValueTypeDataMerger<byte>(options);
            using var pointer = new UnmanagedMemoryPointer<byte>(6);

            dataMerger.Append(new byte[] { 1, 2, 3 });
            dataMerger.Take(pointer.DataPtr, 2);
            string str1 = string.Join(",", pointer.GetSpan().ToArray());

            dataMerger.Append(new byte[] { 4, 5, 6 });
            dataMerger.Take(pointer.DataPtr, 2);
            string str2 = string.Join(",", pointer.GetSpan().ToArray());

            //dataMerger.Take(pointer.DataPtr, 6);
            //string str3 = string.Join(",", pointer.GetSpan().ToArray());

            dataMerger.Append(new byte[] { 7, 8, 9 });
            dataMerger.Take(pointer.DataPtr, 6);
            string str4 = string.Join(",", pointer.GetSpan().ToArray());
        }

        private void btnTakeTail2_Click(object sender, RoutedEventArgs e)
        {
            var options = new ValueTypeDataMergerOptions() { InitCapcity = 5, LimitCapcity = 5 };
            using var dataMerger = new ValueTypeDataMerger<byte>(options);
            using var pointer = new UnmanagedMemoryPointer<byte>(6);

            dataMerger.Append(new byte[] { 1, 2, 3 });
            dataMerger.TakeTail(pointer.DataPtr, 2);
            string str1 = string.Join(",", pointer.GetSpan().ToArray());

            dataMerger.Append(new byte[] { 4, 5, 6 });
            dataMerger.TakeTail(pointer.DataPtr, 2);
            string str2 = string.Join(",", pointer.GetSpan().ToArray());

            //dataMerger.TakeTail(pointer.DataPtr, 6);
            //string str3 = string.Join(",", pointer.GetSpan().ToArray());

            dataMerger.Append(new byte[] { 7, 8, 9 });
            dataMerger.TakeTail(pointer.DataPtr, 6);
            string str4 = string.Join(",", pointer.GetSpan().ToArray());

        }
    }
}
